#include "Facet.h"
#include "Error.h"
#include <GL/gl.h>
#include <iostream>
#include "Soup.h"
#include "UtilGL.h"
#include <math.h>


using namespace std;
using namespace prog3d;


const AVertex &Facet::vertexList() {
  return vv;
}

const Vector3 &Facet::normal() {
  return n;
}

const AVector3 &Facet::normalList() {
  return vn;
}



/** Tableau de facettes */
void AFacet::draw() {
  AFacet::iterator itf;
  if (drawMode & DRAW_GRID) {
    glEnable(GL_POLYGON_OFFSET_FILL);
    glPolygonOffset(1,1);
  }
  for(itf=begin();itf!=end();itf++) {
  	(*itf)->setDrawMode(drawMode);
    (*itf)->draw();
  }
  if (drawMode & DRAW_GRID) {
    glPushAttrib(GL_LIGHTING_BIT);
    glDisable(GL_POLYGON_OFFSET_FILL);
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
    glDisable(GL_LIGHTING);
    glColor3f(0.0,0.0,0.0);
    glLineWidth(2.0);
    for(itf=begin();itf!=end();itf++) {
      (*itf)->draw();
    }
    glLineWidth(1.0);
    glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
    glPopAttrib();
  }
}

void AFacet::drawNormal(float k) {
	AFacet::iterator itf;
  for(itf=begin();itf!=end();itf++) {
    (*itf)->drawNormal(k);
  }
}

void AFacet::setDrawMode(unsigned int mode) {
	drawMode|=mode;
}


void AFacet::computeNormal() {
   AFacet::iterator itf;
   for(itf=begin();itf!=end();itf++) {
     (*itf)->computeNormal();
   }
}


/** Les facettes */
Facet::~Facet() {
   vv.clear(); // !!!!! do not delete the vertices in vv (can be shared vertices)
}


void Facet::print(const string &mesg) {
	cout << "Facet " << mesg << " =(";
	for(unsigned int i=0;i<nbVertex();i++) {
		cout << vv[i]->point();
	}
	cout << ")" << endl;
}

void Facet::triangulate() {
    if (nbVertex()>3) {
        Vertex *s0=*(vertexBegin());
        AVertex::iterator i=vertexBegin()+2;
        Facet *f;
        do {
            f=owner()->createFacet();
            f->addVertex(s0);
            f->addVertex(*i);
            f->addVertex(*(i+1));
            i++;
        } while ((i+1)!=vertexEnd());
        vv.erase(vertexBegin()+3,vertexEnd());

    }
}

bool Facet::isEmpty() const {
	return (vv.size()==0);
}

unsigned int Facet::nbVertex() const {
	return vv.size();
}

unsigned int Facet::nbNormal() const {
  return vn.size();
}

bool Facet::isNormal() const {
  return (vn.size()!=0);
}

void Facet::setNormal(const Vector3 &v) {
	n=v;
}

void Facet::setDrawMode(unsigned int mode) {
	drawMode=mode;
}

void Facet::clearVVertex() {
    vv.clear();
}

void Facet::clearVNormal() {
    vn.clear();
}

void Facet::clear() {
	vv.clear();
	vn.clear();
	vt.clear();
}


void Facet::init(Soup *o) {
    vv.clear();
    vn.clear();
    vt.clear();
    _material=NULL;
    drawMode = NORMAL_VERTEX | DRAW_FILL;
    _owner=o;
}

Facet::Facet(Soup *o) {
    init(o);
}


Facet::Facet(Soup *o,const Vector3 &a,const Vector3 &n) {
  init(o);
    this->a=a;
    this->n=n;
}

Vertex *Facet::createVertex(const Vector3 &p) {
	Vertex *v=owner()->createVertex(p);
	addVertex(v);
	return v;
}


AVertex::iterator Facet::vertexBegin() {
    return vv.begin();
}

AVertex::iterator Facet::vertexEnd() {
    return vv.end();
}

void Facet::addTexCoord(Vector3 *v) {
  vt.push_back(v);
}

Vector3 *Facet::texCoord(unsigned int i) const {
  return vt[i];
}

void Facet::addVertex(Vertex *v) {
    vv.push_back(v);
}

const Vector3 &Facet::normal() const {
    return n;
}

Vector3 *Facet::getNormal(int i) const {
    return vn[i];
}

Vertex *Facet::getVertex(unsigned int i) const {
	return vv[i];
}

const Vector3 &Facet::point(unsigned int i) const {
	return vv[i]->point();
}

AVertex &Facet::getAllVertex() {
    return vv;
}

void Facet::addNormal(Vector3 *v) {
    vn.push_back(v);
}

void Facet::computeNormal() {
  Vector3 s1;
  Vector3 s2;
  Vector3 s3;

  double dist=0;

  AVertex::iterator it1=vv.begin();
  AVertex::iterator it2=vv.begin()+1;
  AVertex::iterator it3=vv.begin()+2;
  bool stop=false;
  while ((dist<1e-05) && !stop) {
    if (it3!=vv.end()) {
        s1=(*(it1))->point();
        s2=(*(it2))->point();
        s3=(*(it3++))->point();
        Vector3 v1(s1,s2);
        Vector3 v2(s2,s3);
        n.cross(v1,v2);
       // cout << s1 << s2 << s3 << n << endl;
        dist=n.length();
        if (it3==vv.end()) {
            it2++;
            if (it2==vv.end()) {
                it1++;
                it2=it1+1;
            }
            it3=it2+1;
        }
    } else {
        stop=true;
        //throw Error("Normal problem",__LINE__,__FILE__);
    }
  }

  if (stop) {
    n.set(0.0,0.0,0.0);
  }
  else  n.scale(1.0/dist);
}


void Facet::material(Material *m) {
  _material=m;
}

Material *Facet::material() {
  return _material;
}

void Facet::draw() {
    AVertex::iterator itv;
/*
    if (drawMode & DRAW_MTL) {
      if (_currentMaterial!=_material) {
        _currentMaterial=_material;
        _material->setGL();
 //       cout << "Material=" << *_material << endl;
        if (drawMode & DRAW_TEXTURE) {
          _material->activeTexture();
        }
      }
    }
*/
    glBegin((drawMode & DRAW_FILL)?GL_POLYGON:GL_LINE_LOOP);
    int k=0;
    unsigned int nbTexCoord=0;
    for(itv=vv.begin();itv!=vv.end();itv++) {
      Vertex *v=*itv;
      if (drawMode & NORMAL_FACE) {
      	glNormal3dv(n.dv());
      } else
      if (vn.size()!=0) {
        glNormal3dv(vn[k]->dv());
        k++;
      }
      else {
        glNormal3dv(v->normal().dv());
      }
      if (drawMode & DRAW_TEXTURE) {
 //       cout << "draw with textures " << endl;
        if (vt.size()!=0) {
          glTexCoord3dv(vt[nbTexCoord]->dv());
          nbTexCoord++;
        }
      }
      glVertex3dv(v->point().dv());
     }
     glEnd();
}

void Facet::eraseDuplicateVertex() {
  unsigned int i=0;
  while (i<nbVertex()) {
    if (vv[i]==vertexSucc(i)) {
      cout << "duplicate" << endl;
      vv.erase(vertexBegin()+i);
      if (vn.size()>0) vn.erase(vn.begin()+i);
      if (vt.size()>0) vt.erase(vt.begin()+i);
    }
    else i++;
  }
}




const Vertex &Facet::vertex(unsigned int i, bool reference) const {
  reference=!reference;
	return *(vv[i]);
}

Vertex *Facet::vertex(unsigned int i) const {
	return vv[i];
}


void Facet::drawNormal(float c) {
    AVertex::iterator itv;
    int k=0;
    for(itv=vv.begin();itv!=vv.end();itv++) {
      Vertex *v=*itv;
      Vector3 p=v->point();
      Vector3 u;
      if (drawMode & NORMAL_FACE) {
      	u=n;
      } else
      if (vn.size()!=0) {
        u=*vn[k];
        k++;
      }
      else {
        u=v->normal();
      }
      UtilGL::drawSegment(v->point(),p+c*u);
     }

}



void Facet::erase(AVertex::iterator &v) {
	vv.erase(v);
}

Vertex *Facet::vertexSucc(int i) {
  int j=i+1;
  if (j<0) return vv[vv.size()-((-j)%vv.size())];
  else return vv[j%vv.size()];
}


Vertex *Facet::vertexPred(int i) {
  int j=i-1;
  if (j<0) return vv[vv.size()-((-j)%vv.size())];
  else return vv[j%vv.size()];
}



unsigned int Facet::indice(unsigned int i) {
  return vv[i]->number();
}


